package com.vcc.service.impl;


import cn.hutool.core.date.DateUtil;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryChain;
import com.mybatisflex.core.update.UpdateChain;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.vcc.core.exception.NotFoundException;
import com.vcc.core.util.IdWorker;
import com.vcc.core.util.RegexUtil;
import com.vcc.data.entity.Cardholder;
import com.vcc.data.entity.Role;
import com.vcc.data.mapper.CardholderMapper;
import com.vcc.service.client.dto.cardholder.ClientCardholderCreateRequest;
import com.vcc.service.client.dto.cardholder.UpdateCardholderDto;
import com.vcc.service.client.dto.cardholder.UpdateCardholderStatusDto;
import com.vcc.service.client.vo.cardholder.CardholderVo;
import com.vcc.service.sa.BossUserUtil;
import com.vcc.service.service.CardholderService;
import org.springframework.stereotype.Service;

import java.util.List;

import static com.vcc.data.entity.table.BossUserTableDef.BOSS_USER;
import static com.vcc.data.entity.table.CardholderTableDef.CARDHOLDER;
import static com.vcc.data.entity.table.UserTableDef.USER;

@Service
public class CardholderServiceImpl extends ServiceImpl<CardholderMapper, Cardholder> implements CardholderService {

    @Override
    public Cardholder getById(Long id) {
        return queryChain().eq(Cardholder::getId, id).oneOpt().orElseThrow(() -> new NotFoundException("没有当前持卡人"));
    }

    @Override
    public Page<Cardholder> paging(Page<Cardholder> pageable, Long targetUserId, Long id) {
        QueryChain<Cardholder> queryChain = queryChain();
        queryChain.leftJoin(USER).on(USER.ID.eq(CARDHOLDER.USER_ID));
        queryChain.leftJoin(BOSS_USER.as("dealer")).on(USER.BE_LONG_TO_DEALER.eq(BOSS_USER.ID));
        queryChain.select(CARDHOLDER.ALL_COLUMNS);
        queryChain.select(USER.EMAIL.as("account"));
        queryChain.select(BOSS_USER.EMAIL.as("dealerAccount"));
        Long bossUserId = BossUserUtil.getIdNotNull();
        if (!BossUserUtil.hasAllData()) {
            queryChain.and(
                    BOSS_USER.as("dealer").ID.eq(bossUserId)
                            .or(BOSS_USER.as("dealer").PARENT_ID.eq(bossUserId)));
        }
        if (RegexUtil.checkObjectIsNotNull(targetUserId)) {
            queryChain.eq(Cardholder::getUserId, targetUserId);
        }
        if (RegexUtil.checkObjectIsNotNull(id)) {
            queryChain.like(Cardholder::getId, id);
        }
        queryChain.orderBy(Cardholder::getCreateDate, false);
        return queryChain.page(pageable);
    }

    @Override
    public Page<CardholderVo> paging(Long userId, Role role, Long targetUserId, Page<CardholderVo> pageable, Long id, String fistName, Integer status, String startDate, String endDate) {
        QueryChain<Cardholder> queryChain = queryChain();
        queryChain.leftJoin(USER).on(USER.ID.eq(CARDHOLDER.USER_ID));
        queryChain.select(CARDHOLDER.ALL_COLUMNS);
        queryChain.select(USER.ACCOUNT.as("account"));
        if (role.getHasAllData()) {
            queryChain.where(
                    USER.PARENT_ID.eq(userId).or(USER.ID.eq(userId))
            );
            if (RegexUtil.checkObjectIsNotNull(targetUserId)) {
                queryChain.eq(Cardholder::getUserId, targetUserId);
            }
        } else {
            queryChain.eq(Cardholder::getUserId, userId);
        }
        if (RegexUtil.checkObjectIsNotNull(id)) {
            queryChain.eq(Cardholder::getId, id);
        }
        if (RegexUtil.checkStringIsNotNull(fistName)) {
            queryChain.like(Cardholder::getFirstName, fistName);
        }
        if (RegexUtil.checkObjectIsNotNull(status)) {
            queryChain.eq(Cardholder::getStatus, status);
        }
        if (RegexUtil.checkStringIsNotNull(startDate) && RegexUtil.checkStringIsNotNull(endDate)) {
            queryChain.between(Cardholder::getCreateDate, DateUtil.beginOfDay(DateUtil.parse(startDate, "yyyy-MM-dd")), DateUtil.endOfDay(DateUtil.parse(endDate, "yyyy-MM-dd")));
        } else if (RegexUtil.checkStringIsNotNull(startDate)) {
            queryChain.ge(Cardholder::getCreateDate, DateUtil.beginOfDay(DateUtil.parse(startDate, "yyyy-MM-dd")));
        } else if (RegexUtil.checkStringIsNotNull(endDate)) {
            queryChain.le(Cardholder::getCreateDate, DateUtil.endOfDay(DateUtil.parse(endDate, "yyyy-MM-dd")));
        }
        queryChain.orderBy(Cardholder::getCreateDate, false);
        return pageAs(pageable, queryChain, CardholderVo.class);
    }

    @Override
    public Boolean updateStatus(UpdateCardholderStatusDto updateCardholderStatusDto) {
        return updateChain().set(Cardholder::getStatus, updateCardholderStatusDto.getStatus()).eq(Cardholder::getId, updateCardholderStatusDto.getId()).update();
    }

    @Override
    public Cardholder createCardholder(Long userId, ClientCardholderCreateRequest clientCardholderCreateRequest) {
        Long id;
        do {
            id = IdWorker.getLongId();
        } while (queryChain().eq(Cardholder::getId, id).exists());
        Cardholder cardholder = new Cardholder();
        cardholder.setId(id);
        cardholder.setUserId(userId);
        cardholder.setFirstName(clientCardholderCreateRequest.getFirstName());
        cardholder.setLastName(clientCardholderCreateRequest.getLastName());
        cardholder.setEmail(clientCardholderCreateRequest.getEmail());
        cardholder.setPhone(clientCardholderCreateRequest.getPhone());
        cardholder.setAddress(clientCardholderCreateRequest.getAddress());
        cardholder.setCountry(clientCardholderCreateRequest.getCountry());
        cardholder.setProvince(clientCardholderCreateRequest.getProvince());
        cardholder.setCity(clientCardholderCreateRequest.getCity());
        cardholder.setArea(clientCardholderCreateRequest.getArea());
        cardholder.setPostCode(clientCardholderCreateRequest.getPostCode());
        cardholder.setRemark(clientCardholderCreateRequest.getRemark());
        cardholder.setStatus(0);
        cardholder.setCardholderInfo(clientCardholderCreateRequest.getCardholderInfo());
        cardholder.setMobilePrefix(clientCardholderCreateRequest.getMobilePrefix());
        cardholder.setBirthday(clientCardholderCreateRequest.getBirthday());
        cardholder.setShareAccountId(clientCardholderCreateRequest.getShareAccountId());
        save(cardholder);
        return cardholder;
    }

    @Override
    public Boolean updateCardholder(Long userId, UpdateCardholderDto updateCardholderDto) {
        Cardholder cardholder = queryChain().eq(Cardholder::getId, updateCardholderDto.getId()).oneOpt().orElseThrow(() -> new NotFoundException("没有当前持卡人信息"));
        UpdateChain<Cardholder> updateChain = updateChain();
        updateChain.eq(Cardholder::getId, cardholder.getId());
        if (RegexUtil.checkStringIsNotNull(updateCardholderDto.getFirstName()) && !cardholder.getFirstName().equals(updateCardholderDto.getFirstName())) {
            if (existsFirstNameByUserId(updateCardholderDto.getFirstName(), userId)) {
                throw new NotFoundException("持卡人名字已存在");
            }
            updateChain.set(Cardholder::getFirstName, updateCardholderDto.getFirstName());
        }
        if (RegexUtil.checkStringIsNotNull(updateCardholderDto.getLastName()) && !cardholder.getLastName().equals(updateCardholderDto.getLastName())) {
            updateChain.set(Cardholder::getLastName, updateCardholderDto.getLastName());
        }
        if (RegexUtil.checkStringIsNotNull(updateCardholderDto.getPhone()) && !cardholder.getPhone().equals(updateCardholderDto.getPhone())) {
            if (existsPhoneByUserId(updateCardholderDto.getPhone(), userId)) {
                throw new NotFoundException("持卡人电话已存在");
            }
            updateChain.set(Cardholder::getPhone, updateCardholderDto.getPhone());
        }
        if (RegexUtil.checkStringIsNotNull(updateCardholderDto.getAddress()) && !cardholder.getAddress().equals(updateCardholderDto.getAddress())) {
            updateChain.set(Cardholder::getAddress, updateCardholderDto.getAddress());
        }
        if (RegexUtil.checkStringIsNotNull(updateCardholderDto.getCountry()) && !cardholder.getCountry().equals(updateCardholderDto.getCountry())) {
            updateChain.set(Cardholder::getCountry, updateCardholderDto.getCountry());
        }
        if (RegexUtil.checkStringIsNotNull(updateCardholderDto.getProvince()) && !cardholder.getProvince().equals(updateCardholderDto.getProvince())) {
            updateChain.set(Cardholder::getProvince, updateCardholderDto.getProvince());
        }
        if (RegexUtil.checkStringIsNotNull(updateCardholderDto.getCity()) && !cardholder.getCity().equals(updateCardholderDto.getCity())) {
            updateChain.set(Cardholder::getCity, updateCardholderDto.getCity());
        }
        if (RegexUtil.checkStringIsNotNull(updateCardholderDto.getArea()) && !cardholder.getArea().equals(updateCardholderDto.getArea())) {
            updateChain.set(Cardholder::getArea, updateCardholderDto.getArea());
        }
        if (RegexUtil.checkStringIsNotNull(updateCardholderDto.getPostCode()) && !cardholder.getPostCode().equals(updateCardholderDto.getPostCode())) {
            updateChain.set(Cardholder::getPostCode, updateCardholderDto.getPostCode());
        }
        if (RegexUtil.checkStringIsNotNull(updateCardholderDto.getRemark()) && !cardholder.getRemark().equals(updateCardholderDto.getRemark())) {
            updateChain.set(Cardholder::getRemark, updateCardholderDto.getRemark());
        }

        if (RegexUtil.checkStringIsNotNull(updateCardholderDto.getMobilePrefix()) && !cardholder.getMobilePrefix().equals(updateCardholderDto.getMobilePrefix())) {
            updateChain.set(Cardholder::getMobilePrefix, updateCardholderDto.getMobilePrefix());
        }
        if (RegexUtil.checkStringIsNotNull(updateCardholderDto.getBirthday()) && !cardholder.getBirthday().equals(updateCardholderDto.getBirthday())) {
            updateChain.set(Cardholder::getBirthday, updateCardholderDto.getBirthday());
        }
        return updateChain.update();
    }

    @Override
    public Boolean existsFirstNameByUserId(String fistName, Long userId) {
        return queryChain().eq(Cardholder::getFirstName, fistName).eq(Cardholder::getUserId, userId).exists();
    }

    @Override
    public Boolean existsLastNameByUserId(String lastName, Long userId) {
        return queryChain().eq(Cardholder::getLastName, lastName).eq(Cardholder::getUserId, userId).exists();
    }

    @Override
    public Boolean existsEmailByUserId(String email, Long userId) {
        return queryChain().eq(Cardholder::getEmail, email).eq(Cardholder::getUserId, userId).exists();
    }

    @Override
    public Boolean existsPhoneByUserId(String phone, Long userId) {
        return queryChain().eq(Cardholder::getPhone, phone).eq(Cardholder::getUserId, userId).exists();
    }

    @Override
    public Cardholder getByEmail(String email) {
        return queryChain().eq(Cardholder::getEmail, email).oneOpt()
                .orElseThrow(() -> new NotFoundException("没有当前持卡人邮箱信息"));
    }

    @Override
    public List<Cardholder> listByFistNameAndUserId(Long userId, String fistName) {
        return queryChain().eq(Cardholder::getUserId, userId).like(Cardholder::getFirstName, fistName).list();
    }

    @Override
    public List<Cardholder> listByEmailAndUserId(Long userId, String email) {
        return queryChain().eq(Cardholder::getUserId, userId).like(Cardholder::getEmail, email).list();
    }

    @Override
    public List<Cardholder> listByUserId(Long userId, Integer status) {
        return queryChain().eq(Cardholder::getUserId, userId).eq(Cardholder::getStatus, status).list();
    }
}
